diff options
Diffstat (limited to 'config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java')
-rw-r--r-- | config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java new file mode 100644 index 00000000000..78c97935d5a --- /dev/null +++ b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java @@ -0,0 +1,399 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config; + +import com.yahoo.foo.MaptypesConfig; +import com.yahoo.test.FunctionTestConfig; +import com.yahoo.test.IntConfig; +import com.yahoo.test.RestartConfig; +import org.junit.Test; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static com.yahoo.test.FunctionTestConfig.BasicStruct; +import static com.yahoo.test.FunctionTestConfig.Enum_val; +import static com.yahoo.test.FunctionTestConfig.Enumarr; +import static com.yahoo.test.FunctionTestConfig.Enumwithdef; +import static com.yahoo.test.FunctionTestConfig.Myarray; +import static com.yahoo.test.FunctionTestConfig.RootStruct; +import static com.yahoo.test.FunctionTestConfig.MyStructMap; +import static com.yahoo.foo.MaptypesConfig.Innermap; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author gjoranv + * @since 5.1.11 + */ +public class ConfigInstanceBuilderTest +{ + + @Test + public void leaf_map_setter_merges_maps() { + MaptypesConfig.Builder builder = new MaptypesConfig.Builder() + .intmap("one", 1); + + Map<String, Integer> newMap = new HashMap<>(); + newMap.put("two", 2); + builder.intmap(newMap); + + MaptypesConfig config = new MaptypesConfig(builder); + assertThat(config.intmap("one"), is(1)); + assertThat(config.intmap("two"), is(2)); + } + + @Test + public void inner_map_setter_merges_maps() { + MaptypesConfig.Builder builder = new MaptypesConfig.Builder() + .innermap("one", new Innermap.Builder() + .foo(1)); + + Map<String, Innermap.Builder> newMap = new HashMap<>(); + newMap.put("two", new Innermap.Builder().foo(2)); + builder.innermap(newMap); + + MaptypesConfig config = new MaptypesConfig(builder); + assertThat(config.innermap("one").foo(), is(1)); + assertThat(config.innermap("two").foo(), is(2)); + } + + @Test + public void testVariableAccessWithBuilder() { + FunctionTestConfig config = createVariableAccessConfigWithBuilder(); + assertVariableAccessValues(config, ":parent:"); + } + + @Test + public void require_that_unset_builder_fields_are_null() throws Exception { + FunctionTestConfig.Builder builder = new FunctionTestConfig.Builder(); + assertNull(getMember(builder, "bool_val")); + assertNull(getMember(builder, "bool_with_def")); + assertNull(getMember(builder, "int_val")); + assertNull(getMember(builder, "int_with_def")); + assertNull(getMember(builder, "long_val")); + assertNull(getMember(builder, "long_with_def")); + assertNull(getMember(builder, "double_val")); + assertNull(getMember(builder, "double_with_def")); + assertNull(getMember(builder, "string_val")); + assertNull(getMember(builder, "stringwithdef")); + assertNull(getMember(builder, "enum_val")); + assertNull(getMember(builder, "enumwithdef")); + assertNull(getMember(builder, "refval")); + assertNull(getMember(builder, "refwithdef")); + assertNull(getMember(builder, "fileVal")); + + BasicStruct.Builder basicStructBuilder = new BasicStruct.Builder(); + assertNull(getMember(basicStructBuilder, "foo")); + assertNull(getMember(basicStructBuilder, "bar")); + } + + @Test + public void require_that_set_builder_fields_are_nonNull() throws Exception { + FunctionTestConfig.Builder builder = createVariableAccessBuilder(); + assertNotNull(getMember(builder, "bool_val")); + assertNotNull(getMember(builder, "bool_with_def")); + assertNotNull(getMember(builder, "int_val")); + assertNotNull(getMember(builder, "int_with_def")); + assertNotNull(getMember(builder, "long_val")); + assertNotNull(getMember(builder, "long_with_def")); + assertNotNull(getMember(builder, "double_val")); + assertNotNull(getMember(builder, "double_with_def")); + assertNotNull(getMember(builder, "string_val")); + assertNotNull(getMember(builder, "stringwithdef")); + assertNotNull(getMember(builder, "enum_val")); + assertNotNull(getMember(builder, "enumwithdef")); + assertNotNull(getMember(builder, "refval")); + assertNotNull(getMember(builder, "refwithdef")); + assertNotNull(getMember(builder, "fileVal")); + + BasicStruct.Builder basicStructBuilder = (BasicStruct.Builder)getMember(builder, "basicStruct"); + assertNotNull(getMember(basicStructBuilder, "foo")); + assertNotNull(getMember(basicStructBuilder, "bar")); + } + + @Test + public void require_that_config_can_be_recreated_from_another_configs_builder() { + FunctionTestConfig original = createVariableAccessConfigWithBuilder(); + FunctionTestConfig copy = new FunctionTestConfig(new FunctionTestConfig.Builder(original)); + assertVariableAccessValues(copy, ":parent:"); + } + + private Object getMember(Object builder, String memberName) throws Exception { + Field field = builder.getClass().getDeclaredField(memberName); + field.setAccessible(true); + return field.get(builder); + } + + static FunctionTestConfig createVariableAccessConfigWithBuilder() { + return new FunctionTestConfig(createVariableAccessBuilder()); + } + + static FunctionTestConfig.Builder createVariableAccessBuilder() { + return new FunctionTestConfig.Builder(). + bool_val(false). + bool_with_def(true). + int_val(5). + int_with_def(-14). + long_val(12345678901L). + long_with_def(-9876543210L). + double_val(41.23). + double_with_def(-12). + string_val("foo"). + stringwithdef("bar and foo"). + enum_val(Enum_val.FOOBAR). + enumwithdef(Enumwithdef.BAR2). + refval(":parent:"). + refwithdef(":parent:"). + fileVal("etc"). + pathVal(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))). + boolarr(false). + longarr(9223372036854775807L). + longarr(-9223372036854775808L). + doublearr(2344.0). + doublearr(123.0). + stringarr("bar"). + enumarr(Enumarr.VALUES). + refarr(Arrays.asList(":parent:", ":parent", "parent:")). // test collection based setter + fileArr("bin"). + intMap("one", 1). + intMap("two", 2). + stringMap("one", "first"). + filemap("f1", "/var"). + filemap("f2", "/store"). + + basicStruct(new BasicStruct.Builder(). + foo("basicFoo"). + bar(3). + intArr(310).intArr(311)). + + rootStruct(new RootStruct.Builder(). + inner0(new RootStruct.Inner0.Builder(). + index(11)). + inner1(new RootStruct.Inner1.Builder(). + index(12)). + innerArr(new RootStruct.InnerArr.Builder(). + boolVal(true). + stringVal("deep")). + innerArr(new RootStruct.InnerArr.Builder(). + boolVal(false). + stringVal("blue a=\"escaped\""))). + + myarray(new Myarray.Builder(). + intval(-5). + stringval("baah"). + stringval("yikes"). + enumval(Myarray.Enumval.INNER). + refval(":parent:"). + fileVal("file0"). + anotherarray(new Myarray.Anotherarray.Builder(). + foo(7)). + myStruct(new Myarray.MyStruct.Builder(). + a(1). + b(2))). + + myarray(new Myarray.Builder(). + intval(5). + enumval(Myarray.Enumval.INNER). + refval(":parent:"). + fileVal("file1"). + anotherarray(new Myarray.Anotherarray.Builder(). + foo(1). + foo(2)). + myStruct(new Myarray.MyStruct.Builder(). + a(-1). + b(-2))). + + myStructMap("one", new MyStructMap.Builder(). + myInt(1). + myString("bull"). + myIntDef(2). + myStringDef("bear"). + anotherMap("anotherOne", new MyStructMap.AnotherMap.Builder(). + anInt(3). + anIntDef(4))); + } + + public static void assertVariableAccessValues(FunctionTestConfig config, String configId) { + assertTrue(config.bool_with_def()); + assertEquals(5, config.int_val()); + assertEquals(-14, config.int_with_def()); + assertEquals(12345678901L, config.long_val()); + assertEquals(-9876543210L, config.long_with_def()); + assertEquals(41.23, config.double_val(), 0.000001); + assertEquals(-12, config.double_with_def(), 0.000001); + assertEquals("foo", config.string_val()); + assertEquals("bar and foo", config.stringwithdef()); + assertEquals(FunctionTestConfig.Enum_val.FOOBAR, config.enum_val()); + assertEquals(FunctionTestConfig.Enumwithdef.BAR2, config.enumwithdef()); + assertEquals(configId, config.refval()); + assertEquals(configId, config.refwithdef()); + assertEquals("etc", config.fileVal().value()); + assertEquals(1, config.boolarr().size()); + assertEquals(1, config.boolarr().size()); // new api with accessor for a List of the original Java type + assertEquals(false, config.boolarr().get(0)); // new List api + assertEquals(false, config.boolarr(0)); // short-hand + assertEquals(0, config.intarr().size()); + assertEquals(2, config.longarr().size()); + assertEquals(Long.MAX_VALUE, config.longarr(0)); + assertThat(config.longarr().get(1), is(Long.MIN_VALUE)); + assertEquals(2, config.doublearr().size()); + assertEquals(1, config.stringarr().size()); + assertEquals(1, config.enumarr().size()); + assertEquals(FunctionTestConfig.Enumarr.VALUES, config.enumarr().get(0)); // new List api, don't have to call value() + assertEquals(3, config.refarr().size()); + assertEquals(1, config.fileArr().size()); + assertEquals(configId, config.refarr(0)); + assertEquals(":parent", config.refarr(1)); + assertEquals("parent:", config.refarr(2)); + assertEquals("bin", config.fileArr(0).value()); + + assertThat(config.intMap("one"), is(1)); + assertThat(config.intMap("two"), is(2)); + assertThat(config.stringMap("one"), is("first")); + assertThat(config.filemap("f1").value(), is("/var")); + assertThat(config.filemap("f2").value(), is("/store")); + assertEquals("basicFoo", config.basicStruct().foo()); + assertEquals(3, config.basicStruct().bar()); // new List api + assertEquals(2, config.basicStruct().intArr().size()); + assertThat(config.basicStruct().intArr().get(0), is(310)); // new List api + assertThat(config.basicStruct().intArr().get(1), is(311)); // new List api + assertEquals(310, config.basicStruct().intArr(0)); // short-hand + assertEquals("inner0", config.rootStruct().inner0().name()); // new List api + assertEquals(11, config.rootStruct().inner0().index()); + assertEquals("inner1", config.rootStruct().inner1().name()); + assertEquals(12, config.rootStruct().inner1().index()); + assertEquals(2, config.rootStruct().innerArr().size()); + assertEquals(true, config.rootStruct().innerArr(0).boolVal()); + assertEquals("deep", config.rootStruct().innerArr(0).stringVal()); + assertEquals(false, config.rootStruct().innerArr(1).boolVal()); + assertEquals("blue a=\"escaped\"", config.rootStruct().innerArr(1).stringVal()); + + assertEquals(2, config.myarray().size()); // new List api + assertEquals(configId, config.myarray().get(0).refval()); // new List api + assertEquals(configId, config.myarray(0).refval()); // short-hand + assertEquals("file0", config.myarray(0).fileVal().value()); + assertEquals(1, config.myarray(0).myStruct().a()); + assertEquals(2, config.myarray(0).myStruct().b()); + assertEquals(configId, config.myarray(1).refval()); + assertEquals("file1", config.myarray(1).fileVal().value()); + assertEquals(-1, config.myarray(1).myStruct().a()); + assertEquals(-2, config.myarray(1).myStruct().b()); + + assertThat(config.myStructMap("one").myInt(), is(1)); + assertThat(config.myStructMap("one").myString(), is("bull")); + assertThat(config.myStructMap("one").myIntDef(), is(2)); + assertThat(config.myStructMap("one").myStringDef(), is("bear")); + assertThat(config.myStructMap("one").anotherMap("anotherOne").anInt(), is(3)); + assertThat(config.myStructMap("one").anotherMap("anotherOne").anIntDef(), is(4)); + } + + private boolean callContainsFieldsFlaggedWithRestart(Class<?> configClass) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method m = configClass.getDeclaredMethod("containsFieldsFlaggedWithRestart"); + m.setAccessible(true); + return (boolean) m.invoke(null); + } + + private ChangesRequiringRestart callGetChangesRequiringRestart(ConfigInstance config1, ConfigInstance config2) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method m = config1.getClass().getDeclaredMethod("getChangesRequiringRestart", config2.getClass()); + m.setAccessible(true); + return (ChangesRequiringRestart) m.invoke(config1, config2); + } + + @Test + public void require_that_config_class_reports_any_restart_values() throws Exception { + assertTrue(callContainsFieldsFlaggedWithRestart(RestartConfig.class)); + assertFalse(callContainsFieldsFlaggedWithRestart(IntConfig.class)); + } + + @Test + public void require_that_config_class_can_make_change_report() throws Exception { + IntConfig noRestart1 = new IntConfig(new IntConfig.Builder().intVal(42)); + IntConfig noRestart2 = new IntConfig(new IntConfig.Builder().intVal(21)); + ChangesRequiringRestart report = callGetChangesRequiringRestart(noRestart1, noRestart2); + assertFalse(report.needsRestart()); + + RestartConfig config1 = new RestartConfig(new RestartConfig.Builder().intVal(42)); + RestartConfig config2 = new RestartConfig(new RestartConfig.Builder().intVal(21)); + report = callGetChangesRequiringRestart(config1, config1); + assertFalse(report.needsRestart()); + report = callGetChangesRequiringRestart(config1, config2); + assertTrue(report.needsRestart()); + + FunctionTestConfig function1 = createVariableAccessConfigWithBuilder(); + FunctionTestConfig.Builder funcBuilder = createVariableAccessBuilder(); + funcBuilder.myStructMap.get("one").myInt(42); + funcBuilder.int_val(100); + funcBuilder.stringarr.set(0, "foo"); + funcBuilder.intMap.put("one", 42); + funcBuilder.intMap.remove("two"); + funcBuilder.intMap.put("three", 3); + funcBuilder.myarray.get(1).intval(17); + funcBuilder.myarray.get(0).anotherarray.get(0).foo(32); + funcBuilder.myarray.add(new Myarray.Builder().refval("refval").fileVal("fileval").myStruct(new Myarray.MyStruct.Builder().a(4))); + funcBuilder.myStructMap.put("new", new MyStructMap.Builder().myString("string").myInt(13)); + funcBuilder.basicStruct(new BasicStruct.Builder().bar(1234)); + FunctionTestConfig function2 = new FunctionTestConfig(funcBuilder); + report = callGetChangesRequiringRestart(function1, function1); + assertFalse(report.needsRestart()); + report = callGetChangesRequiringRestart(function1, function2); + assertTrue(report.needsRestart()); + assertEquals("function-test", report.getName()); + assertThat( + report.toString(), + startsWith( + "# An int value\n" + + "# Also test that multiline comments\n" + + "# work.\n" + + "function-test.int_val has changed from 5 to 100\n" + + "function-test.stringarr[0] has changed from \"bar\" to \"foo\"\n" + + "# This is a map of ints.\n" + + "function-test.intMap{one} has changed from 1 to 42\n" + + "# This is a map of ints.\n" + + "function-test.intMap{two} with value 2 was removed\n" + + "# This is a map of ints.\n" + + "function-test.intMap{three} was added with value 3\n" + + "# A basic struct\n" + + "function-test.basicStruct.foo has changed from \"basicFoo\" to \"basic\"\n" + + "function-test.basicStruct.bar has changed from 3 to 1234\n" + + "function-test.basicStruct.intArr[0] with value 310 was removed\n" + + "function-test.basicStruct.intArr[1] with value 311 was removed\n" + + "function-test.myarray[0].anotherarray[0].foo has changed from 7 to 32\n" + + "# This is my array\n" + + "function-test.myarray[1].intval has changed from 5 to 17\n" + + "function-test.myarray[2] was added with value \n" + ) + ); + + assertThat( + report.toString(), + containsString( + "function-test.myStructMap{one}.myInt has changed from 1 to 42\n" + + "function-test.myStructMap{new} was added with value \n" + ) + ); + + funcBuilder.myStructMap.remove("one"); + FunctionTestConfig function3 = new FunctionTestConfig(funcBuilder); + report = callGetChangesRequiringRestart(function2, function3); + assertEquals(1, report.getReportLines().size()); + assertThat( + report.toString(), + containsString("function-test.myStructMap{one} with value \n") + ); + } +} |